/*
 * Copyright (C) 2010 Moduad Co., Ltd.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.androidpn.server.xmpp.push;

import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.UUID;

import org.androidpn.server.model.ChatMessage;
import org.androidpn.server.model.Notification;
import org.androidpn.server.model.User;
import org.androidpn.server.service.*;
import org.androidpn.server.util.Constants;
import org.androidpn.server.xmpp.session.ClientSession;
import org.androidpn.server.xmpp.session.SessionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
import org.xmpp.packet.IQ;

/**
 * This class is to manage sending the notifcations to the users.
 *
 * @author Sehwan Noh (devnoh@gmail.com)
 */
public class NotificationManager {

    private static final String NOTIFICATION_NAMESPACE = "androidpn:iq:notification";

    private static final String CHATMSG_NAMESPACE = "androidpn:iq:chatmsg";

    private final Log log = LogFactory.getLog(getClass());

    private SessionManager sessionManager;

    private NotificationService notificationService;

    private ChatMsgService chatMsgService;

    private UserService userService;

    /**
     * Constructor.
     */
    public NotificationManager() {
        sessionManager = SessionManager.getInstance();
        notificationService = ServiceLocator.getNotificationService();
        chatMsgService = ServiceLocator.getChatMsgService();
        userService = ServiceLocator.getUserService();
    }

    /**
     * 向全部用户推送通知.
     *
     * @param apiKey  the API key
     * @param title   标题
     * @param message 内容
     * @param uri     Url
     */
    public void sendBroadcast(String apiKey, String title, String message,
                              String uri, String msgFrom) {
        log.debug("sendBroadcast()...");
        System.out.println(Constants.getFormatDate() + "\n" + msgFrom);
        List<User> users = userService.getUsers();
        for (User user : users) {
            Random random = new Random();
            String id = Integer.toHexString(random.nextInt());
            saveNotification(apiKey, user.getUsername(), title, message, uri, id);//必须在前面，否则有个小bug
            IQ notificationIQ = createNotificationIQ(id, apiKey, title, message, uri, msgFrom);
            ClientSession session = sessionManager.getSession(user.getUsername());
            if (session != null && session.getPresence().isAvailable()) {
                notificationIQ.setTo(session.getAddress());
                session.deliver(notificationIQ);
            }

        }
    }

    /**
     * 向一个用户推送通知.
     *
     * @param apiKey  the API key
     * @param title   题目
     * @param message 内容
     * @param uri     Url
     */
    public void sendNotifcationToUser(String apiKey, String username,
                                      String title, String message, String uri, boolean shouldSave, String msgFrom) {
        log.debug("sendNotifcationToUser()...");
        Random random = new Random();
        String id = Integer.toHexString(random.nextInt());
        IQ notificationIQ = createNotificationIQ(id, apiKey, title, message, uri, msgFrom);
        ClientSession session = sessionManager.getSession(username);
        if (session != null) {
            if (session.getPresence().isAvailable()) {
                notificationIQ.setTo(session.getAddress());
                session.deliver(notificationIQ);
            }
        }
        try {
            User user = userService.getUserByUsername(username);
            if (user != null && shouldSave) {
                saveNotification(apiKey, username, title, message, uri, id);
            }
        } catch (UserNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void sendChatMsgFromWeb(String fromUserId, String toUserId, String message) {
        System.out.println("sendChatMsgToUser...");
        Random random = new Random();
        String uuid = null;
        boolean chat = true;
        while (chat) {
            try {
                uuid =  UUID.randomUUID().toString();
                ChatMessage chatMessage = chatMsgService.getChatMessageByUuid(uuid);
                if(chatMessage == null){
                    chat = false;
                }
            } catch (ChatMsgNotFoundException e) {
                e.printStackTrace();
            }
        }
        String chatDate = Constants.getFormatDate();
        IQ chatMsgIQ = createChatMsgIQ(toUserId, fromUserId, chatDate, message, "true", uuid);

        ClientSession session = sessionManager.getSession(toUserId);
        if (session != null) {
            if (session.getPresence().isAvailable()) {
                System.out.println("session is Useable...");
                chatMsgIQ.setTo(session.getAddress());
                session.deliver(chatMsgIQ);
            }
        }
        saveChatMsg(fromUserId, toUserId, message, chatDate, "true", uuid);
    }

    public void sendChatMsgToUser(String fromUserId, String toUserId, String message, String chatDate, String chatType, String uuid) {
        log.debug("sendChatMsgToUser...");
        IQ chatMsgIQ = createChatMsgIQ(toUserId, fromUserId, chatDate, message, chatType, uuid);
        ClientSession session = sessionManager.getSession(toUserId);
        if (session != null) {
            if (session.getPresence().isAvailable()) {
                chatMsgIQ.setTo(session.getAddress());
                session.deliver(chatMsgIQ);
            }
        }
    }

    private void saveChatMsg(String fromUserId, String toUserId, String message, String chatDate, String chatType, String uuid) {
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setFromUser(fromUserId);
        chatMessage.setToUser(toUserId);
        chatMessage.setMsgDate(chatDate);
        chatMessage.setMessage(message);
        chatMessage.setUuid(uuid);
        chatMessage.setMsgType(Boolean.parseBoolean(chatType));
        chatMsgService.saveChatMessage(chatMessage);
    }

    /**
     * 根据标签推送
     *
     * @param apiKey
     * @param tag
     * @param title
     * @param message
     * @param uri
     * @param shouldSave
     */
    public void sendNotificationByTag(String apiKey, String tag,
                                      String title, String message, String uri, boolean shouldSave) {
        Set<String> usernameSet = sessionManager.getUsernamessByTag(tag);
        if (usernameSet != null && !usernameSet.isEmpty()) {
            for (String username : usernameSet) {
                sendNotifcationToUser(apiKey, username, title, message, uri, shouldSave, null);
            }
        }
    }

    /**
     * 给离线用户存储消息在数据库
     *
     * @param apiKey
     * @param username
     * @param title
     * @param message
     * @param uri
     */
    public void saveNotification(String apiKey, String username,
                                 String title, String message, String uri, String uuid) {
        Notification notification = new Notification();
        notification.setApiKey(apiKey);
        notification.setUsername(username);
        notification.setTitle(title);
        notification.setMessage(message);
        notification.setUri(uri);
        notification.setUuid(uuid);
        notificationService.saveNotification(notification);
    }

    /**
     * 根据别名推送消息
     *
     * @param apiKey
     * @param alias
     * @param title
     * @param message
     * @param uri
     * @param shouldSave
     */
    public void sendNotificationByAlias(String apiKey, String alias,
                                        String title, String message, String uri, boolean shouldSave) {
        String username = sessionManager.getUsernameByAlias(alias);
        if (username != null) {
            sendNotifcationToUser(apiKey, username, title, message, uri, shouldSave, null);
        }
    }

    /**
     * Creates a new notification IQ and returns it.
     */
    private IQ createNotificationIQ(String id, String apiKey, String title,
                                    String message, String uri, String from) {
        // String id = String.valueOf(System.currentTimeMillis());

        Element notification = DocumentHelper.createElement(QName.get(
                "notification", NOTIFICATION_NAMESPACE));
        notification.addElement("id").setText(id);
        notification.addElement("apiKey").setText(apiKey);
        notification.addElement("title").setText(title);
        notification.addElement("message").setText(message);
        notification.addElement("uri").setText(uri);
        notification.addElement("from").setText(from);
        String date = Constants.getFormatDate();
        notification.addElement("date").setText(date);

        IQ iq = new IQ();
        iq.setType(IQ.Type.set);
        iq.setChildElement(notification);

        return iq;
    }

    private IQ createChatMsgIQ(String toUserName, String fromuser, String date, String message, String msgtype, String uuid) {
        Element chatmsg = DocumentHelper.createElement(QName.get(
                "chatmsg", CHATMSG_NAMESPACE));
        chatmsg.addElement("chatto").setText(toUserName);
        chatmsg.addElement("chatfrom").setText(fromuser);
        chatmsg.addElement("chatdate").setText(date);
        chatmsg.addElement("message").setText(message);
        chatmsg.addElement("msgtype").setText(msgtype);
        chatmsg.addElement("uuid").setText(uuid);
        IQ iq = new IQ();
        iq.setType(IQ.Type.set);
        iq.setChildElement(chatmsg);
        return iq;
    }
}
